"""
日志记录工具
"""
import logging
import logging.handlers
import os
from datetime import datetime
from typing import Optional, Dict, Any
from functools import wraps
import time
import inspect
import json
import threading
from collections import deque
from queue import Queue
from contextvars import ContextVar

from fastapi import Request
from .config import get_settings

# 创建上下文变量来存储当前请求
current_request: ContextVar[Optional[Request]] = ContextVar('current_request', default=None)

# 获取配置
settings = get_settings()

# 异步日志队列
_log_queue = Queue(maxsize=1000)
_log_writer_thread = None
_log_writer_running = False

def _log_writer_worker():
    """异步日志写入工作线程"""
    global _log_writer_running
    _log_writer_running = True
    
    while _log_writer_running:
        try:
            # 从队列获取日志记录
            log_record = _log_queue.get(timeout=1)
            if log_record is None:  # 停止信号
                break
            
            logger, level, message = log_record
            if level == "error":
                logger.error(message)
            elif level == "warning":
                logger.warning(message)
            elif level == "info":
                logger.info(message)
            else:
                logger.info(message)
                
        except Exception as e:
            # 队列为空或其他错误，继续运行
            continue
    
    _log_writer_running = False

def _start_log_writer():
    """启动异步日志写入线程"""
    global _log_writer_thread
    if _log_writer_thread is None or not _log_writer_thread.is_alive():
        _log_writer_thread = threading.Thread(target=_log_writer_worker, daemon=True)
        _log_writer_thread.start()

def _log_async(logger, level: str, message: str):
    """异步写入日志"""
    try:
        _log_queue.put((logger, level, message), timeout=0.1)
    except:
        # 队列满，直接丢弃日志
        pass

def get_caller_info(skip_frames: int = 2) -> Dict[str, str]:
    """获取调用者的文件名、行号和函数名"""
    frame = inspect.currentframe()
    try:
        # 跳过指定数量的帧栈
        for _ in range(skip_frames):
            frame = frame.f_back
            if frame is None:
                break
        
        if frame is None:
            return {"filename": "unknown", "lineno": 0, "funcName": "unknown"}
        
        return {
            "filename": os.path.basename(frame.f_code.co_filename),
            "lineno": frame.f_lineno,
            "funcName": frame.f_code.co_name
        }
    finally:
        del frame


def format_json_log(data: Dict[str, Any], caller_info: Dict[str, str]) -> str:
    """格式化JSON日志输出，使其更易读"""
    # 创建格式化的日志条目
    log_entry = {
        "timestamp": data.get("timestamp", datetime.now().isoformat()),
        "level": data.get("level", "INFO"),
        "location": f"{caller_info['filename']}:{caller_info['lineno']}:{caller_info['funcName']}",
        "message": data.get("message", ""),
    }
    
    # 添加其他字段
    for key, value in data.items():
        if key not in ["timestamp", "level", "message"]:
            log_entry[key] = value
    
    # 格式化为易读的JSON字符串
    return json.dumps(log_entry, ensure_ascii=False, indent=2)


class APILogger:
    """API日志记录器"""
    def __init__(self):
        self.logger = logging.getLogger("api_logger")
        self.logger.setLevel(logging.INFO)
        
        # 避免重复添加处理器
        if not self.logger.handlers:
            # 创建日志目录
            log_dir = os.path.dirname(settings.log_file)
            if log_dir and not os.path.exists(log_dir):
                os.makedirs(log_dir)
            
            # 创建文件处理器
            file_handler = logging.handlers.RotatingFileHandler(
                settings.log_file,
                maxBytes=10 * 1024 * 1024,  # 10MB
                backupCount=5
            )
            
            # 创建格式化器
            formatter = logging.Formatter(
                '%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(funcName)s - %(message)s'
            )
            
            file_handler.setFormatter(formatter)
            self.logger.addHandler(file_handler)
            
            # 添加控制台处理器（仅在生产环境添加）
            if settings.debug:
                console_handler = logging.StreamHandler()
                console_handler.setFormatter(formatter)
                self.logger.addHandler(console_handler)
            
            # 防止日志传播到根日志记录器
            self.logger.propagate = False
            
            # 启动异步日志写入线程
            _start_log_writer()
    
    def log_api_call(
        self,
        endpoint: str,
        method: str,
        user_id: Optional[int],
        request_data: Optional[Dict[str, Any]],
        response_data: Optional[Dict[str, Any]],
        status_code: int,
        response_time: float,
        ip_address: Optional[str] = None,
        user_agent: Optional[str] = None
    ):
        """记录API调用"""
        log_data = {
            "timestamp": datetime.now().isoformat(),
            "endpoint": endpoint,
            "method": method,
            "user_id": user_id,
            "status_code": status_code,
            "response_time": response_time,
            "ip_address": ip_address,
            "user_agent": user_agent
        }
        
        if request_data:
            log_data["request_data"] = request_data
        
        if response_data:
            # 只记录部分响应数据，避免日志过大
            if isinstance(response_data, dict) and len(str(response_data)) > 1000:
                log_data["response_data"] = {"truncated": True, "size": len(str(response_data))}
            else:
                log_data["response_data"] = response_data
        
        # 记录到文件日志
        if status_code >= 400:
            _log_async(self.logger, "error", f"API Call Failed: {log_data}")
        else:
            _log_async(self.logger, "info", f"API Call Success: {log_data}")
        
        # 写入数据库
        try:
            from core.database import SessionLocal
            from models.database import APILog
            from sqlalchemy.orm import Session
            
            # 获取数据库会话
            db = SessionLocal()
            
            try:
                # 创建API日志记录
                api_log = APILog(
                    user_id=user_id,
                    endpoint=endpoint,
                    method=method,
                    request_data=request_data,
                    response_data=response_data,
                    status_code=status_code,
                    response_time=response_time,
                    ip_address=ip_address,
                    user_agent=user_agent
                )
                
                # 添加到数据库
                db.add(api_log)
                db.commit()
                
            except Exception as db_error:
                db.rollback()
                # 如果数据库写入失败，至少记录到文件日志
                _log_async(self.logger, "error", f"Failed to write API log to database: {str(db_error)}")
            finally:
                db.close()
                
        except Exception as e:
            # 如果数据库连接失败，至少记录到文件日志
            _log_async(self.logger, "error", f"Failed to connect to database for API logging: {str(e)}")
    
    def log_error(self, error: Exception, context: Optional[Dict[str, Any]] = None):
        """记录错误（包含详细堆栈跟踪）"""
        import traceback
        
        # 获取真实调用位置
        caller_info = get_caller_info(skip_frames=3)
        
        error_data = {
            "level": "ERROR",
            "message": f"Error occurred: {type(error).__name__}",
            "error_type": type(error).__name__,
            "error_message": str(error),
            "context": context or {},
            "stack_trace": traceback.format_exc(),
            "error_module": error.__class__.__module__ if hasattr(error, '__class__') else None
        }
        
        # 记录详细错误信息（使用格式化的JSON）
        formatted_log = format_json_log(error_data, caller_info)
        _log_async(self.logger, "error", formatted_log)
        
        # 如果是数据库错误，记录额外的数据库相关信息
        if "IntegrityError" in type(error).__name__:
            db_error_data = {
                "level": "ERROR",
                "message": "Database integrity error details",
                "original_error": str(getattr(error, 'orig', 'No original error')),
                "sql_statement": getattr(error, 'statement', 'No statement available'),
                "parameters": getattr(error, 'params', 'No parameters available')
            }
            db_formatted_log = format_json_log(db_error_data, caller_info)
            _log_async(self.logger, "error", db_formatted_log)
    
    def log_task_event(self, task_id: str, event: str, data: Optional[Dict[str, Any]] = None):
        """记录任务事件"""
        # 获取真实调用位置
        caller_info = get_caller_info(skip_frames=3)
        
        log_data = {
            "level": "INFO",
            "message": f"Task Event: {event}",
            "task_id": task_id,
            "event": event,
            "data": data or {}
        }
        
        # 记录任务事件（使用格式化的JSON）
        formatted_log = format_json_log(log_data, caller_info)
        _log_async(self.logger, "info", formatted_log)


class TaskLogger:
    """任务日志记录器"""
    
    def __init__(self, task_id: str):
        self.task_id = task_id
        self.logger = logging.getLogger(f"task_{task_id}")
        self.logger.setLevel(logging.INFO)
        
        # 创建任务日志文件
        log_file = f"logs/tasks/{task_id}.log"
        os.makedirs(os.path.dirname(log_file), exist_ok=True)
        
        file_handler = logging.FileHandler(log_file)
        formatter = logging.Formatter(
            '%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(funcName)s - %(message)s'
        )
        file_handler.setFormatter(formatter)
        self.logger.addHandler(file_handler)
    
    def info(self, message: str, data: Optional[Dict[str, Any]] = None):
        """记录信息日志"""
        log_data = {"message": message}
        if data:
            log_data["data"] = data
        self.logger.info(log_data)
    
    def error(self, message: str, error: Optional[Exception] = None, data: Optional[Dict[str, Any]] = None):
        """记录错误日志"""
        log_data = {"message": message}
        if error:
            log_data["error"] = str(error)
            log_data["error_type"] = type(error).__name__
        if data:
            log_data["data"] = data
        self.logger.error(log_data)
    
    def warning(self, message: str, data: Optional[Dict[str, Any]] = None):
        """记录警告日志"""
        log_data = {"message": message}
        if data:
            log_data["data"] = data
        self.logger.warning(log_data)


# 创建全局日志记录器
api_logger = APILogger()


def log_api_call(func):
    """API调用日志装饰器"""
    @wraps(func)
    async def wrapper(*args, **kwargs):
        start_time = time.time()
        
        # 从上下文变量中获取当前请求
        request = current_request.get()
        
        endpoint = ""
        method = ""
        user_id = None
        ip_address = None
        user_agent = None
        request_data = None
        
        if request:
            endpoint = request.url.path
            method = request.method
            ip_address = request.client.host if request.client else None
            user_agent = request.headers.get("user-agent")
            
            # 获取用户信息
            try:
                # 从请求状态中获取用户ID
                user_id = getattr(request.state, 'user_id', None)
                # 如果没有，尝试从请求头中获取
                if not user_id:
                    auth_header = request.headers.get("authorization")
                    if auth_header and auth_header.startswith("Bearer "):
                        token = auth_header[7:]
                        # 这里可以添加JWT解析逻辑来获取用户ID
                        # 暂时跳过，因为需要导入auth模块
            except:
                pass
            
            # 提取请求数据
            try:
                if method in ["POST", "PUT", "PATCH"]:
                    # 对于有请求体的方法，尝试获取JSON数据
                    if hasattr(request, '_json'):
                        request_data = request._json
                    else:
                        # 如果没有解析的JSON，尝试从表单数据中获取
                        form_data = await request.form()
                        if form_data:
                            request_data = dict(form_data)
            except:
                # 如果无法获取请求数据，记录查询参数
                try:
                    request_data = dict(request.query_params)
                except:
                    pass
        
        try:
            # 执行函数
            result = await func(*args, **kwargs)
            
            # 记录成功日志
            response_time = time.time() - start_time
            api_logger.log_api_call(
                endpoint=endpoint,
                method=method,
                user_id=user_id,
                request_data=request_data,
                response_data=result if isinstance(result, dict) else None,
                status_code=200,
                response_time=response_time,
                ip_address=ip_address,
                user_agent=user_agent
            )
            
            return result
            
        except Exception as e:
            import traceback
            
            # 记录错误日志（包含详细堆栈跟踪）
            error_context = {
                "endpoint": endpoint,
                "method": method,
                "user_id": user_id,
                "ip_address": ip_address,
                "user_agent": user_agent
            }
            api_logger.log_error(e, error_context)
            
            # 记录API调用日志（错误情况，包含详细错误信息）
            response_time = time.time() - start_time
            error_response = {
                "error": str(e),
                "error_type": type(e).__name__,
                "error_module": e.__class__.__module__ if hasattr(e, '__class__') else None,
                "stack_trace": traceback.format_exc() if settings.debug else "Stack trace available in logs"
            }
            
            api_logger.log_api_call(
                endpoint=endpoint,
                method=method,
                user_id=user_id,
                request_data=request_data,
                response_data=error_response,
                status_code=500,
                response_time=response_time,
                ip_address=ip_address,
                user_agent=user_agent
            )
            raise
    
    return wrapper


def get_task_logger(task_id: str) -> TaskLogger:
    """获取任务日志记录器"""
    return TaskLogger(task_id)


def get_logger(name: str = __name__) -> logging.Logger:
    """获取标准日志记录器"""
    logger = logging.getLogger(name)
    logger.setLevel(logging.INFO)
    
    # 如果logger没有处理器且根logger也没有处理器，添加默认处理器
    if not logger.handlers and not logging.getLogger().handlers:
        # 创建格式化器
        formatter = logging.Formatter(
            '%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(funcName)s - %(message)s'
        )
        
        # 创建控制台处理器
        console_handler = logging.StreamHandler()
        console_handler.setFormatter(formatter)
        logger.addHandler(console_handler)
    
    return logger


def setup_logging():
    """设置日志配置"""
    # 创建日志目录
    os.makedirs("logs/tasks", exist_ok=True)
    os.makedirs("logs/api", exist_ok=True)
    
    # 配置根日志记录器
    logging.basicConfig(
        level=getattr(logging, settings.log_level),
        format='%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(funcName)s - %(message)s',
        handlers=[
            logging.FileHandler(settings.log_file)
        ]
    )


if __name__ == "__main__":
    setup_logging()
    test_logger = APILogger()
    test_logger.log_api_call(
        endpoint="/test",
        method="GET",
        user_id=1,
        request_data={"test": "data"},
        response_data={"result": "success"},
        status_code=200,
        response_time=0.1,
        ip_address="127.0.0.1"
    )